<script lang="ts">
import { defineComponent, ref, computed, onMounted, watch } from 'vue'
import type { PropType } from 'vue'

interface ChromaticTextProps {
  text: string;
  colors?: string[];
  speed?: number;
  angle?: number;
  strokeWidth?: number;
  fontSize?: string | number;
}

export default defineComponent({
  name: 'ChromaticText',
  props: {
    text: {
      type: String,
      required: true,
      validator: (value: string) => value.trim().length > 0
    },
    colors: {
      type: Array as PropType<string[]>,
      default: () => ['#ff6b6b', '#4ecdc4', '#45b7d1', '#96f2d7'],
      validator: (value: unknown) =>
          Array.isArray(value) && value.every(c => typeof c === 'string' && c.startsWith('#'))
    },
    speed: {
      type: Number,
      default: 5,
      validator: (value: number) => value > 0 && value <= 10
    },
    angle: {
      type: Number,
      default: 90,
      validator: (value: number) => value >= 0 && value <= 360
    },
    strokeWidth: {
      type: Number,
      default: 2,
      validator: (value: number) => value >= 0 && value <= 10
    },
    fontSize: {
      type: [String, Number] as PropType<string | number>,
      default: undefined,
      validator: (value: unknown) => {
        if (typeof value === 'string') {
          return /^(\d+(\.\d+)?(px|rem|em|%|vw|vh)|calc$.+$)$/.test(value)
        }
        return typeof value === 'number' && value > 0
      }
    }
  },
  setup(props: ChromaticTextProps) {
    const textElement = ref<HTMLElement | null>(null)

    // 安全颜色列表
    const safeColors = computed(() => {
      if (!props.colors || !Array.isArray(props.colors)) return ['#fff']
      return props.colors.filter(c =>
          typeof c === 'string' && /^#([0-9A-F]{3}){1,2}$/i.test(c)
      )
    })

    // 动态样式计算
    const textStyles = computed(() => {
      const styles: Record<string, string> = {
        '--stroke-width': `${props.strokeWidth}px`,
        '--animation-speed': `${props.speed}s`
      }

      if (props.fontSize !== undefined) {
        styles.fontSize = typeof props.fontSize === 'number'
            ? `${props.fontSize}px`
            : props.fontSize
      }

      return styles
    })

    // 生成渐变背景
    const createGradient = () => {
      const colors = safeColors.value
      if (colors.length === 0) return 'linear-gradient(90deg, #fff, #fff)'

      return colors.length === 1
          ? `linear-gradient(${props.angle}deg, ${colors}, ${colors})`
          : `linear-gradient(${props.angle}deg, ${colors.join(', ')})`
    }

    // 更新渐变样式
    const updateGradient = () => {
      if (textElement.value) {
        textElement.value.style.setProperty('--gradient', createGradient())
      }
    }

    // 生命周期钩子
    onMounted(updateGradient)

    // 响应颜色/角度变化
    watch([safeColors, () => props.angle], updateGradient)

    return {
      textElement,
      textStyles
    }
  }
})
</script>


<template>
  <div class="chromatic-text-wrapper">
    <span
        ref="textElement"
        class="chromatic-text"
        :style="textStyles"
    >
      {{ text }}
    </span>
  </div>
</template>

<style lang="scss" scoped>
.chromatic-text-wrapper {
  display: inline-block;
  position: relative;
  filter: url(#goo); /* SVG滤镜容器 */

  &::before {
    content: "";
    position: absolute;
    inset: -8px;
    background: inherit;
    filter: blur(12px);
    opacity: 0.6;
    z-index: -1;
    mix-blend-mode: screen;
  }
}

.chromatic-text {
  --gradient: linear-gradient(90deg, #ff6b6b, #4ecdc4, #45b7d1, #96f2d7);
  --stroke-width: 2px;
  --animation-speed: 5s;

  /* 文字基础样式 */
  font: {
    family: 'Arial Rounded MT Bold', system-ui, sans-serif;
    size: clamp(2rem, 5vw, 4rem); /* 响应式字体 */
    weight: 900;
  }
  letter-spacing: 0.08em;
  text-transform: uppercase;

  /* 渐变效果 */
  background-image: var(--gradient);
  background-size: 300% 100%;
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  position: relative;
  animation: chromatic-flow var(--animation-speed) ease-in-out infinite;

  /* 3D立体效果 */
  text-shadow:
      0.05em 0.05em 0.1em rgba(0,0,0,0.3),
      0 0 0.2em currentColor,
      0 0 0.8em rgba(255,255,255,0.4);

  /* 描边容器 */
  &::after {
    content: attr(data-text);
    position: absolute;
    top: 0;
    left: 0;
    z-index: -1;
    color: transparent;
    -webkit-text-stroke: var(--stroke-width) rgba(255,255,255,0.8);
    filter: drop-shadow(0 0 4px rgba(255,255,255,0.3));
  }

  /* 硬件加速优化 */
  transform: translateZ(0);
  backface-visibility: hidden;
}

@keyframes chromatic-flow {
  0%, 100% {
    background-position: 0% 50%;
    filter: hue-rotate(0deg);
  }
  50% {
    background-position: 100% 50%;
    filter: hue-rotate(15deg);
  }
}

/* 移动端优化 */
@media (max-width: 768px) {
  .chromatic-text {
    --stroke-width: 1.5px;
    text-shadow:
        0.03em 0.03em 0.05em rgba(0,0,0,0.3),
        0 0 0.15em currentColor;

    &::after {
      -webkit-text-stroke-width: 1px;
    }
  }
}

</style>

